pub mod env;
pub mod value;
pub mod ops;

mod test;

use std::{rc::Rc, result};

pub use env::{Env, EnvExt};
pub use value::{Lambda, Symbol, Value};

use crate::Expr;

pub type Result<T> = result::Result<T, Error>;
pub type EvalResult = Result<Value>;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error(transparent)]
    Env(#[from] env::Error),
    #[error(transparent)]
    Value(#[from] value::Error),
    #[error("Too few arguments on {func}, require {needs}.")]
    TooFewArguments { func: &'static str, needs: usize },
    #[error("Pop from empty exprs")]
    PopFromEmptyExprs,
    #[error("User custom: {0}")]
    Custom(String),
}

pub trait Appliable {
    fn apply(&mut self, env: Rc<Env>, exprs: Vec<Expr>) -> EvalResult;
}
